﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Luna.Framework.Manifest;
using System.Collections.Specialized;
using System.Reflection;

namespace Luna.Framework.Impl.UriResolvers {
	public class NewUriResolver: IUriResolver {

		public bool supportScheme(string scheme) {
			return "new".Equals(scheme) || "new-by-template".Equals(scheme) || "template".Equals(scheme);
		}

		public object resolveObject(IAppContext context, Uri uri, object data) {
			object obj = null;
			if ("new".Equals(uri.Scheme))
				obj = newObject(context, uri);
			else if ("new-by-template".Equals(uri.Scheme) || "template".Equals(uri.Scheme))
				obj = newObjectByTemplate(context, uri);
			if (obj != null && uri.Query.isNotNullAndEmpty()) {
				string query = uri.Query.Substring(1);
				foreach(string pair in query.Split('&'))
					if (pair.isNotNullAndEmpty() && pair.IndexOf('=') > 0) {
						int idx = pair.IndexOf('=');
						string pName = pair.Substring(0, idx);
						string pValue = pair.Substring(idx + 1);
						PropertyInfo propInfo = obj.getMember<PropertyInfo>(pName, false);
						if (propInfo != null)
							propInfo.SetValue(obj, pValue.convertTo(propInfo.PropertyType), null);
					}
			}
			return obj;
		}

		private object newObjectByTemplate(IAppContext context, Uri uri) {
			return createObjectFromTemplate(context, uri.Segments[1]);
		}

		private object createObjectFromTemplate(IAppContext context, string templateId, object obj = null) {
			IConfigurationManifest manifest = Framework.Manifest.getManifest(templateId);
			if (manifest != null) {
				string[] parentTemplates = manifest.getProperty<string>("inherit", "").Split(',');
				if (manifest.Type != null || obj != null) {
					if (obj == null) {
						obj = Activator.CreateInstance(manifest.Type);
						obj.setPropertyValue("Context", context, null);
					}
					obj = manifest.applyManifest(context, obj);
					foreach (string pId in parentTemplates) 
						if (pId.Trim().Length > 0) 
							obj = createObjectFromTemplate(context, pId.Trim(), obj);
				}
				else if (parentTemplates.Length > 1)
					throw new Exception("Confused to determine target object type for template: " + templateId);
				else if (parentTemplates.Length == 0)
					throw new Exception("Unable to determine target object type for template: " + templateId);
				else {
					obj = createObjectFromTemplate(context, parentTemplates[0].Trim());
					manifest.applyManifest(context, obj);
				}
			}
			return obj;
		}

		private object newObject(IAppContext context, Uri uri) {
			string asm = uri.Host;
			string typeName = uri.Segments[1];
			Type type = Type.GetType(typeName + ", " + asm);
			if (type != null) {
				object obj = Activator.CreateInstance(type);
				obj.setPropertyValue("Context", context, null);
				return obj;
			}
			return null;
		}
	}
}
